package com.hgd.security.evp.auth.config;

import com.hgd.security.evp.auth.authentication.HgdAuthenticationFailureHandler;
import com.hgd.security.evp.auth.authentication.HgdAuthenticationSuccessHandler;
import com.hgd.security.evp.auth.interf.AuthorizePermitAntMatchersHandler;
import com.hgd.security.evp.auth.properties.PropertiesConfig;
import com.hgd.security.evp.auth.provider.HgdDaoAuthenticationProvider;
import com.hgd.security.evp.auth.service.IUserService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.password.PasswordEncoder;

import java.util.ArrayList;
import java.util.Arrays;

/**
 * @author By 尚
 * @date 2019/3/29 0:39
 */
@Configuration
@Slf4j
@ConditionalOnBean(value = PasswordEncoder.class)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private IUserService userService;

    @Autowired
    private PasswordEncoder passwordEncoder;

    @Autowired
    private HgdAuthenticationSuccessHandler hgdAuthenticationSuccessHandler;

    @Autowired
    private HgdAuthenticationFailureHandler hgdAuthenticationFailureHandler;

    @Autowired
    private HgdDaoAuthenticationProvider hgdDaoAuthenticationProvider;

    @Autowired
    private PropertiesConfig propertiesConfig;

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.
            formLogin().
            successHandler(hgdAuthenticationSuccessHandler).failureHandler(hgdAuthenticationFailureHandler).
            loginPage("/authentication/require").// 对于某一请求，如果在未登陆的情况下进行的，Security会进行拦截，并中转到该处配置的地址进行处理
            loginProcessingUrl("/check/login").// 登陆成功后的请求，这个请求由Security进行处理，并将登陆成功后的信息进行保存
                                            // 如果想自行处理登陆成功后的逻辑，可在此处配置为自己的地址
            and().authorizeRequests().antMatchers(

            propertiesConfig.getAntMatchers().toArray(new String[1])

//                "/login", //
//            "/static/**", //
//            "/view/**", //
//            "/js/**", //
//            "/home",  // 将首页地址也放权，这样可以进入首页index.js，发送ajax请求，从而捕获请求返回信息
//            "/css", //
//            "/image", //
//            "/authentication/require", // 用户登录为/authentication/require，所以应该放权，否则会不停重定向，形成死循环
//            "/authentication/logout" // 将登出成功请求放权，否则登出后，该请求会被拦截，跳转到/authentication/require

        ).
            permitAll() //以上配置的路径全部放权
            .and().authorizeRequests().anyRequest().authenticated() // 除了以上antMatchers配置的路径外，其它的任何请求需求认证
            // 以下配置登出，invalidateHttpSession当登出时清除登录状态
            .and().logout().logoutUrl("/logout").logoutSuccessUrl("/authentication/logout").invalidateHttpSession(true)
            // spring Security下，X-Frame-Options默认为DENY,即拒绝当前页面加载任何Frame页面，该配置对其放行
            .and().headers().frameOptions().disable() //
            .and().csrf().disable();
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        log.debug("=====自定义用户密码加密方式:org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder=====");
        hgdDaoAuthenticationProvider.setUserDetailsService(userService);
        hgdDaoAuthenticationProvider.setPasswordEncoder(passwordEncoder);
        hgdDaoAuthenticationProvider.setHideUserNotFoundExceptions(false);
        auth.authenticationProvider(hgdDaoAuthenticationProvider);
        super.configure(auth);
    }
}
